/*******************************************************************************
 * File name:     mci.c
 * Description:
 * Project:       mci_new
 * Target:        LPC2478
 * Compiler:      arm-none-eabi-gcc
 * Date:          28-05-2012
 * Author:        Kuba
 * Based on:      ---
 ******************************************************************************/

/*==============================================================================
 Includes
==============================================================================*/
# include <string.h>
# include <stdbool.h>
# include "LPC24xx.h"
# include "hdr_scb.h"
# include "gpdma.h"
# include "typedef.h"
# include "printf.h"

# include "mci.h"

/*==============================================================================
 Defines
==============================================================================*/
/* GPDMA can use internal RAM or external RAM. If you use GPDMA, you can */
/* set 1 next to your choice. */
/* choose only one kind of RAM */
# define MCI_DMA_IRAM                  0        /* internal RAM */
# define MCI_DMA_XRAM                  1        /* external RAM */

# if (MCI_DMA_IRAM == 1) && (MCI_DMA_XRAM == 1)
# error "Choose only one type of GPDMA RAM"
# endif

/* masks */
# define MCI_PINSEL2_MASK     0x3C0FCF0            /* mask for PINSEL2 */
# define MCI_DATA_LEN_MASK    0x0000FFFF           /* mask for MCI_DATA_LEN reserved bits */

# define MCI_WHOLE_STATUS   (MCI_CLEAR_CMD_CRC_FAIL_CLR                       \
                  | MCI_CLEAR_DATA_CRC_FAIL_CLR | MCI_CLEAR_CMD_TIMEOUT_CLR   \
                  | MCI_CLEAR_DATA_TIMEOUT_CLR | MCI_CLEAR_TX_UNDERRUN_CLR    \
                  | MCI_CLEAR_RX_OVERRUN_CLR | MCI_CLEAR_CMD_RESP_END_CLR     \
                  | MCI_CLEAR_CMD_SENT_CLR | MCI_CLEAR_DATA_END_CLR           \
                  | MCI_CLEAR_START_BIT_ERR_CLR | MCI_CLEAR_DATA_BLOCK_END_CLR)

# define DATA_END_INT_MASK ((MCI_STATUS_DATA_END) | (MCI_STATUS_DATA_BLOCK_END))

# define ERR_TX_INT_MASK   ((MCI_STATUS_DATA_CRC_FAIL) | (MCI_STATUS_DATA_TIMEOUT)  | \
                           (MCI_STATUS_TX_UNDERRUN) | (MCI_STATUS_START_BIT_ERR))

# define ERR_RX_INT_MASK   ((MCI_STATUS_DATA_CRC_FAIL) | (MCI_STATUS_DATA_TIMEOUT)  | \
                           (MCI_STATUS_RX_OVERRUN) | (MCI_STATUS_START_BIT_ERR))

# define CMD_INT_MASK      ((MCI_STATUS_CMD_CRC_FAIL) | (MCI_STATUS_CMD_TIMEOUT)    | \
                           (MCI_STATUS_CMD_RESP_END) | (MCI_STATUS_CMD_SENT)        | \
                           (MCI_STATUS_CMD_ACTIVE))

# define DATA_ERR_INT_MASK ((MCI_STATUS_DATA_CRC_FAIL) | (MCI_STATUS_DATA_TIMEOUT)  | \
                           (MCI_STATUS_TX_UNDERRUN) | (MCI_STATUS_RX_OVERRUN)       | \
                           (MCI_STATUS_START_BIT_ERR))

# define SEND_IF_COND_ARG  0x000001AA
# define TIMEOUT_VAL       1000

/* operating speeds */
/* MCLK - MCI clock domain
 * MCLK = CCLK (72 MHz) - as PINSEL0/1 = 0x55555555 (see init.c)
 * MCLCLK frequency = MCLK/[2*(MCI_CLK_DIV_NORMAL_SPEED_SD + 1)]
 * 72 / (2 * 4) = 9
 * 72 / (2 * 3) = 12
 * 72 / (2 * 2) = 18
 */
# define MCI_CLK_DIV_NORMAL_SPEED_SD   (0x4-1)
# define MCI_CLK_DIV_NORMAL_SPEED_MMC  (0x4-1)
# define MCI_CLK_DIV_LOW_SPEED         (0x60-1)

/* relative card address for MMC cards */
# define MMC_CARD_ADDRESS              0x12340000

/* card block size should not be changed */
/* 1 block = 512 bytes- which is the most common value for many cards */
# define CARD_BLOCK_SIZE               512

# if MCI_DMA_IRAM
# define MCI_BLOCKS_NUM                8
# if MCI_BLOCKS_NUM > 8
# error "GPDMA IRAM buffer is max 8 blocks"
# endif
# endif /* end of MCI_DMA_IRAM */

# if MCI_DMA_XRAM
# define MCI_BLOCKS_NUM                32
# if MCI_BLOCKS_NUM >= 128
# error "Blocks number is limited by MCI_DATA_LEN (16 bit)"
# endif
# endif /* end of MCI_DMA_XRAM */

/*==============================================================================
 Types
==============================================================================*/
/* commands for card */
enum cmdList {
   cmdGO_IDLE_STATE        = 0,
   cmdSEND_OP_COND         = 1,
   cmdALL_SEND_CID         = 2,
   cmdSET_RELATIVE_ADDR    = 3,
   cmdSET_ACMD_BUS_WIDTH   = 6,
   cmdSELECT_CARD          = 7,
   cmdSEND_IF_COND         = 8,
   cmdSEND_CSD             = 9,
   cmdSTOP_TRANSMISSION    = 12,
   cmdSEND_STATUS          = 13,
   cmdSET_BLOCK_LEN        = 16,
   cmdREAD_SINGLE_BLOCK    = 17,
   cmdREAD_MUL_BLOCKS      = 18,
   cmdWRITE_SINGLE_BLOCK   = 24,
   cmdWRITE_MUL_BLOCKS     = 25,
   cmdSEND_APP_OP_COND     = 41,
   cmdAPP_CMD              = 55
};

/* enum response defines what respons is expected from card */
enum response {
   respNO_RESPONSE      = 0,
   respSHORT_RESPONSE   = MCI_COMMAND_RESPONSE,
   respLONG_RESPONSE    = (MCI_COMMAND_RESPONSE | MCI_COMMAND_LONG_RSP)
};

/* card register OCR- Operating Conditions Register */
enum cardOCR {
   ocrHIGH_VOLTAGE   = 0x00FF8000,        /* high voltage range: 2.7 - 3.6V */
   ocrHIGH_CAPACITY  = 0x40000000,        /* card high capacity status bit */
   ocrCARD_NOT_BUSY  = 0x80000000         /* card power up status bit */
};

/* card status register */
enum cardStatus {
   csREADY_4_DATA    = (1 << 8),
   csTRAN_STATE      = (4 << 9),
   csTRAN_STATE_MASK = 0x1E00,
   csDATA_STATE      = (5 << 9)
};

/* MCI bus can be 1-bit or 4-bit width */
enum mciBusWidth {
   mciBUS_1BIT = 0,
   mciBUS_4BIT = 0x2
};

/* card type is detected in mciCardInit- this info goes to card struct */
/* see SD PHY, page 34 for detecting specific types during init process */
enum cardType {
   cardNO_CARD,         /* no card in slot */
   cardUNKNOWN,         /* unknown card */
   cardMMC,             /* MMC card */
   cardSD_V2,           /* SD version 2.0 */
   cardSDSC_V1,         /* SDSC version 1.0 */
   cardSDSC_V2,         /* SDSC version 2.0 */
   cardSDHC            /* SDHC */
};

/* CSD bits 127:126, which comes to MCI_RESP0 as 31:30 means:
 * 00 - CSD ver 1.0
 * 01 - CSD ver 2.0
 * other- reserved */
enum csdVer {
   csdVER1  = 0,
   csdVER2  = 0x40000000,
   csdUNKNOWN
};

/* this struct is filled by mciCardInit and contains info about card */
struct cardInfo {
   enum cardType  type;             /* card type: MMC, SDSC, SDHC */
   uint32         capacity;         /* capacity in blocks, block is 512 bytes */
   uint32         address;          /* card address */
   enum csdVer    csdVer;
};

/*==============================================================================
 Globals
==============================================================================*/
/* mciBlkEndFlag is used by mciIsr to detect end of transmission */
static volatile bool mciBlkEndFlag = FALSE;
static volatile bool mciDataEndFlag = FALSE;

/* card stores info about detected card if any */
static struct cardInfo card;

/* GPDMA configuration */
static struct gpdmaConf mciDmaTxConf;
static struct gpdmaConf mciDmaRxConf;
/* GDPMA channel settings */
static gpdmaChannel mciTxChnl;
static gpdmaChannel mciRxChnl;
/* GPDMA buffers placed in external RAM, which starts at 0xA0000000 */
uint8 mciDmaTxBuff [CARD_BLOCK_SIZE * MCI_BLOCKS_NUM] __attribute__ ((section(".mciTxXRam")));
uint8 mciDmaRxBuff [CARD_BLOCK_SIZE * MCI_BLOCKS_NUM] __attribute__ ((section(".mciRxXRam")));

/*==============================================================================
 Static ISR prototypes
==============================================================================*/
static void mciIsr(void) __attribute__ ((interrupt("IRQ")));

/*==============================================================================
 Static function prototypes
==============================================================================*/
static uint32  mciSendCmd     (enum cmdList cmdIndex, uint32 arg, enum response resp);
static bool    deselectCard   (void);
static bool    checkTranState (void);
static bool    mciDmaTxBlks   (uint32 sector, const struct gpdmaConf *gpdma);
static bool    mciDmaRxBlks   (uint32 sector, const struct gpdmaConf *gpdma);
static bool    mciTxBlk       (const uint8 *tx, uint32 block);
static bool    mciRxBlock     (uint8 *rx, uint32 block);
/* functions used by mciIsr */
static void    dataErrProcess (void);
static void    dataEndProcess (void);
static void    cmdProcess     (void);

static void    dummyService   (void);

/*==============================================================================
 Global function definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 function name:   mciInit
 description:     init MCI controller
 parameters:      IRQ priority
 returned value:  true or false
------------------------------------------------------------------------------*/
bool mciInit (enum priority priority)
{
   volatile uint32 i;

   /* set MCI pins */
   /* clear PINSEL2's MCI pins */
   PINSEL2 &= ~MCI_PINSEL2_MASK;
   /* set MCI pins */
   PINSEL2 |= (PINSEL2_MCICLK | PINSEL2_MCICMD | PINSEL2_MCIPWR | PINSEL2_MCIDAT0
               |PINSEL2_MCIDAT1 | PINSEL2_MCIDAT2 | PINSEL2_MCIDAT3);

   PCONP |= PCONP_PCSDC;                           /* turn on MCI */

   MCI_COMMAND = 0;                                /* reset command register */
   MCI_DATA_CTRL = 0;                              /* and data control register */
   MCI_CLEAR = MCI_WHOLE_STATUS;                   /* clear all pending interrupts */
   MCI_POWER = MCI_POWER_CTRL_POWEROFF;            /* turn power off */
   for (i = 0; i < 5000; ++i);
   MCI_POWER |= MCI_POWER_CTRL_POWERUP;            /* enable power */
   while (!(MCI_POWER & MCI_POWER_CTRL_POWERUP));  /* wait if power is not up */
   for (i = 0; i < 1000; ++i);
   /* set clock to 400kHz, enable MCI bus clock, disable clock if bus is idle,
      no bypass, no wide bus */
   MCI_CLOCK = (MCI_CLOCK_ENABLE | MCI_CLOCK_PWR_SAVE | (MCI_CLK_DIV_LOW_SPEED));
   for (i = 0; i < 2400; ++i);
   MCI_POWER |= MCI_POWER_CTRL_POWERON;
   for (i = 0; i < 50000; ++i);
   /* init MCI interrutps */
   return (irqInit (irqMCI, (void *) mciIsr, priority));
}

/*------------------------------------------------------------------------------
 function name:   mciCardInit
 description:     detect what card is used and init it
 parameters:      GPDMA support on/off
 returned value:  true or false
------------------------------------------------------------------------------*/
bool mciCardInit (enum mciDma dma)
{
   volatile uint32 i;
   uint32 status;                      /* card status */
   uint32 response;                    /* card response */
   uint32 cmd41Arg;                    /* argument to init card */
   uint8 cSizeMulti;                   /* to calculate card capacity */
   uint16 cSize, blockLen;             /* to calculate card capacity */

   /* default values */
   card.type = cardNO_CARD;
   card.address = 0;
   card.capacity = 0;
   card.csdVer = csdUNKNOWN;

   /* card detection starts here */
   /*** send CMD0 ***/
   status = mciSendCmd (cmdGO_IDLE_STATE, 0, respNO_RESPONSE);
   for (i = 0; i < 2400; ++i);
   /* during the init process the host is not allowed to change the voltage */
   /* set push-pull bus mode for SD cards and disable Rod */
   MCI_POWER &= ~(MCI_POWER_OPEN_DRAIN | MCI_POWER_ROD);
   for (i = 0; i < TIMEOUT_VAL; ++i);


   /* initialization for SD cards >= v2.00 - *must* be done first! */
   /* send power range (2.7 - 3.6V) to card; may time out if:
      - card cannot operate within the power range or
      - card does not understand CMD8 (MMC and pre-v2.00 SD cards) */

  /* verify SD's operating conditions */
   /*** send CMD8 ***/
  status = mciSendCmd (cmdSEND_IF_COND, SEND_IF_COND_ARG, respSHORT_RESPONSE);
  if (status & MCI_STATUS_CMD_TIMEOUT)
  {
     /* no response means timeout */
     /* it's not an SD card, so don't check HCS bit (Host Capacity Support)
      *  for high capacity */
     cmd41Arg = ocrHIGH_VOLTAGE;
  }
  else
  {
     /* there is a response (no timeout) */
     /* this must be a SD card >= v2.00, so check for high capacity
      * the HCS bit set to 1 indicates SDHC or SDXC support (0 - SDSC) */
     card.type = cardSD_V2;
     cmd41Arg = (ocrHIGH_CAPACITY | ocrHIGH_VOLTAGE);
  }


  /* test for the cards power range- it works also for older SD cards */
  /* send power range (2.7 - 3.6V) to card; may time out if:
     - card cannot operate within the power range or
     - card does not understand ACMD41 (MMC cards) */
  /*** send ACMD41 ***/
  i = TIMEOUT_VAL;
  do
  {
     /* CMD55 must always precede ACMD41*/
     /* send CMD55 */
     status = mciSendCmd (cmdAPP_CMD, 0, respSHORT_RESPONSE);
     /* send ACMD41 */
     status = mciSendCmd (cmdSEND_APP_OP_COND, cmd41Arg, respSHORT_RESPONSE);
     response = MCI_RESP0;
  } while (!(status & MCI_STATUS_CMD_TIMEOUT) && !(response & ocrCARD_NOT_BUSY) && --i);

  /* timeout? */
  if ((status & MCI_STATUS_CMD_TIMEOUT) || (i == 0))
  {
     /* CMD55/ACMD41 timeout - so it's either:
      - an MMC card
      - an SD card with incompatible power range
      - or no card at all */

     /* set open drain bus mode and enable Rod for MMC initialization */
     MCI_POWER |= (MCI_POWER_OPEN_DRAIN | MCI_POWER_ROD);
     for (i = 0; i < TIMEOUT_VAL; ++i);
     i = TIMEOUT_VAL;
     do
     {
        /* send CMD1 */
        status = mciSendCmd (cmdSEND_OP_COND, ocrHIGH_VOLTAGE, respSHORT_RESPONSE);
        response = MCI_RESP0;
     } while (!(status & MCI_STATUS_CMD_TIMEOUT) && !(response & ocrCARD_NOT_BUSY) && --i);

     /* again timeout? */
     if  ((status & MCI_STATUS_CMD_TIMEOUT) || (i == 0))
     {
        card.type = cardNO_CARD;
        return (FALSE);                /* no card at all */
     }
     else
     {
        card.type = cardMMC;          /* it's MMC */
     }
  }
  /* no timeout - it's SD */
  else
  {
     if (response & ocrHIGH_CAPACITY)
     {
        card.type = cardSDHC;
     }
     else
     {
        card.type = cardSDSC_V1;
     }
  }


  /* get CID- Card IDentification register */
  /*** send CMD2 ***/
  status = mciSendCmd (cmdALL_SEND_CID, 0, respLONG_RESPONSE);
  if (!(status & MCI_STATUS_CMD_RESP_END))
  {
     return (FALSE); /* no response */
  }
  /* CID data can be extracted here */

  /* get RCA- Relative Card Address */
  /*** send CMD3 ***/
  switch (card.type)
  {
  case cardMMC:
     /* MMC cards need the RCA to be set by the host */
     status = mciSendCmd (cmdSET_RELATIVE_ADDR, MMC_CARD_ADDRESS, respSHORT_RESPONSE);
     /* short response R1 expected */
     break;

  case cardSD_V2: /* I meant that- fall through */
  case cardSDSC_V1:
  case cardSDSC_V2:
  case cardSDHC:
     /* it's SD, get address from the card */
     status = mciSendCmd (cmdSET_RELATIVE_ADDR, 0, respSHORT_RESPONSE);
     /* short response R6 expected */
     break;

  default:
     return (FALSE);
  }
  if (status & MCI_STATUS_CMD_RESP_END)      /* there is a response */
  {
     switch (card.type)
     {
     case cardMMC:
        card.address = MMC_CARD_ADDRESS;
        break;

     case cardSD_V2: /* I meant that- fall through */
     case cardSDSC_V1:
     case cardSDSC_V2:
     case cardSDHC:
        card.address = (MCI_RESP0 & 0xFFFF0000);
        break;

     default:
        return (FALSE);
     }
  }
  else
  {
     return (FALSE); /* no response */
  }


  /* set clock speed- init requires slow speed, enable MCI bus clock
   * disable clock if bus is idle, no bypass, no wide bus */
  switch (card.type)
  {
  case cardMMC:
     /* max frequency is 20 MHz */
     MCI_CLOCK = (MCI_CLOCK_ENABLE | MCI_CLOCK_PWR_SAVE | (MCI_CLK_DIV_NORMAL_SPEED_MMC));
     for (i = 0; i < TIMEOUT_VAL; ++i);
     /* set push-pull bus mode and disable Rod */
     MCI_POWER &= ~(MCI_POWER_OPEN_DRAIN | MCI_POWER_ROD);
     for (i = 0; i < TIMEOUT_VAL; ++i);
     break;

  case cardSD_V2: /* I meant that- fall through */
  case cardSDSC_V1:
  case cardSDSC_V2:
  case cardSDHC:
     /* max frequency is 25 MHz */
     MCI_CLOCK = (MCI_CLOCK_ENABLE | MCI_CLOCK_PWR_SAVE | (MCI_CLK_DIV_NORMAL_SPEED_SD));
     for (i = 0; i < TIMEOUT_VAL; ++i);
     break;

  default:
     return (FALSE);
  }


  /* get CSD- Card Specific Data register- to count card capacity */
  /*** send CMD9 ***/
  status = mciSendCmd (cmdSEND_CSD, card.address, respLONG_RESPONSE);
  if (status & MCI_STATUS_CMD_RESP_END)         /* there is a response */
  {
     switch (card.type)
     {
     case cardMMC:
        /* CSD structure for MMC cards */
        blockLen = (MCI_RESP1 & 0x000F0000) >> 16;
        cSize = (MCI_RESP1 & 0x000003FF) << 2;
        cSize |= (MCI_RESP2 & 0xC0000000) >> 30;
        cSizeMulti = (MCI_RESP2 & 0x00038000) >> 15;
        /* for formula see SD Specification Part 1: Physical Layer V2.00, p. 99 */
        card.capacity = ((1 << blockLen) * (cSize + 1) * (1 << (cSizeMulti + 2))) / CARD_BLOCK_SIZE;
        break;

     case cardSD_V2: /* I meant that- fall through */
     case cardSDSC_V1:
     case cardSDSC_V2:
     case cardSDHC:
        /* CSD structure for SD cards- SD PHY, page 108 */
        blockLen = (MCI_RESP1 & 0x000F0000) >> 16;
        /* actually, for c_size we should also read the lower 6 bits of MCI_RESP1,
          but these are specified to be constantly '0' in CSD v2.0, so we ignore them */
        cSize = (MCI_RESP2 & 0xFFFF0000) >> 16;
        /* for formula see SD Specification Part 1: Physical Layer V2.00, p. 99 */
        card.capacity = (cSize + 1) * (1 << blockLen) * (1024 / CARD_BLOCK_SIZE);
        /* get CSD version- mask out all but 31:30 bits (127:126) */
        response = (MCI_RESP0 & 0xC0000000);
        switch (response)
        {
        case csdVER1:
           card.csdVer = csdVER1;
           break;

        case csdVER2:
           card.csdVer = csdVER2;
           break;

        default:
           card.csdVer = csdUNKNOWN;
           break;
        }
        break;

     default:
        card.capacity = 0;
        return (FALSE);
     }
  }
  else
  {
     return (FALSE); /* no response */
  }

  if (dma == mciDMA_ENABLE)
  {
     /* to work with GPDMA MCI needs 4 bit bus */
     status = mciSendCmd (cmdSELECT_CARD, card.address, respSHORT_RESPONSE);
     if (!(status & MCI_STATUS_CMD_RESP_END))
     {
        return (FALSE); /* no response */
     }

     /* turn on 4 bit mode */
     switch (card.type)
     {
     case cardMMC:
        return (FALSE);

     case cardSD_V2: /* I meant that- fall through */
     case cardSDSC_V1:
     case cardSDSC_V2:
     case cardSDHC:
        MCI_CLOCK |= MCI_CLOCK_WIDE_BUS;
        for (i = 0; i < TIMEOUT_VAL; ++i);
        /* send CMD55 */
        mciSendCmd (cmdAPP_CMD, card.address, respSHORT_RESPONSE);
        /* send ACMD6 */
        status = mciSendCmd (cmdSET_ACMD_BUS_WIDTH, mciBUS_4BIT, respSHORT_RESPONSE);
        break;

     default:
        return (FALSE);
     }
     if (!(status & MCI_STATUS_CMD_RESP_END))
     {
        return (FALSE); /* no response */
     }

     /* config GPDMA */
     //mciDmaTxConf.channel          = gpdmaCH0;
     mciDmaTxConf.mode             = gpdmaM2P;
     mciDmaTxConf.srcWidth         = gpdmaS_WIDTH32;
     mciDmaTxConf.dstWidth         = gpdmaD_WIDTH32;
     mciDmaTxConf.sbSize           = gpdmaSB_SIZE4;  /* internal GPDMA fifo is 4 word deep */
     mciDmaTxConf.dbSize           = gpdmaDB_SIZE8;  /* MCI fifo is 16 words deep, 32 bit wide */
     mciDmaTxConf.srcPeriph        = 0;
     mciDmaTxConf.dstPeriph        = gpdmaDST_PERIPH_SD_MMC;
     mciDmaTxConf.flowCtrl         = gpdmaFLOW_CTRL_M2P_P;
     mciDmaTxConf.srcAddr          = (uint32) mciDmaTxBuff;
     mciDmaTxConf.dstAddr          = (uint32) &MCI_FIFO;
     mciDmaTxConf.transferEndService = dummyService;
     mciDmaTxConf.errorService     = dummyService;

     //mciDmaRxConf.channel          = gpdmaCH1;
     mciDmaRxConf.mode             = gpdmaP2M;
     mciDmaRxConf.srcWidth         = gpdmaS_WIDTH32;
     mciDmaRxConf.dstWidth         = gpdmaD_WIDTH32;
     mciDmaRxConf.sbSize           = gpdmaSB_SIZE8;
     mciDmaRxConf.dbSize           = gpdmaDB_SIZE4;
     mciDmaRxConf.srcPeriph        = gpdmaSRC_PERIPH_SD_MMC;
     mciDmaRxConf.dstPeriph        = 0;
     mciDmaRxConf.flowCtrl         = gpdmaFLOW_CTRL_P2M_P;
     mciDmaRxConf.srcAddr          = (uint32) &MCI_FIFO;
     mciDmaRxConf.dstAddr          = (uint32) mciDmaRxBuff;
     mciDmaRxConf.transferEndService = dummyService;
     mciDmaRxConf.errorService     = dummyService;
  }
  return (TRUE);
}

/*------------------------------------------------------------------------------
 function name:   mciCardInfo
 description:     display information about card
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
void mciCardInfo (void)
{
   switch (card.type)
   {
   case cardNO_CARD:
      uprintf ("%s\n", "No card detected");
      break;

   case cardUNKNOWN:
      uprintf ("%s\n", "Unknown card");
      break;

   case cardMMC:
      uprintf ("%s\n", "MMC card");
      break;

   case cardSD_V2:
      uprintf ("%s\n", "SD v2.00 card");
      break;

   case cardSDSC_V1:
      uprintf ("%s\n", "SDSC v1.x card");
      break;

   case cardSDSC_V2:
      uprintf ("%s\n", "SDSC v2.00 card");
      break;

   case cardSDHC:
      uprintf ("%s\n", "SDHC card");
      break;

   default:
      uprintf ("%s\n", "Unknown error");
      break;

   }

   switch (card.csdVer)
   {
   case csdVER1:
      uprintf ("%s\n", "CSD v 1.0");
      break;

   case csdVER2:
      uprintf ("%s\n", "CSD v 2.0");
      break;

   case csdUNKNOWN:
      uprintf ("%s\n", "Unknown CSD");
      break;
   }
   uprintf ("address: %x\ncapacity: %d\n", card.address, card.capacity);
}

/*------------------------------------------------------------------------------
 function name:   mciDmaWrite2Card
 description:     function writes n bytes from src address to card. One write
                   is always CARD_BLOCK_SIZE * maxBlksNum. For example:
                   if user needs to write 100 bytes, function rounds the number
                   to 16384 up. If user needs to write 17000 bytes, function
                   rounds the number to 32768 bytes (16384 * 2)
 parameters:      source pointer, size in bytes
 returned value:  last written block
------------------------------------------------------------------------------*/
int32 mciDmaWrite2Card (uint8 *src, uint32 sector, uint32 size)
{
   uint32 div, i;

   /* calculate number of memory chunks to write- 1 chunk is 512 * 32 bytes */
   /* check how many chunks write- if remainder is not 0 */
   if (size % (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM))
   {
      /* round up- one memory chunk'll be added */
      div = (size / (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM)) + 1;
   }
   else
   {
      div = (size / (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM));
   }

   /* write div times, each write is 512 bytes * 32 blocks */
   for (i = 0; i < div; ++i)
   {
      /* copy to GPDMA TX buffer contents from the MCI TX buffer, size is 512 * 32 */
      memcpy ((void *)mciDmaTxConf.srcAddr , src + (i * CARD_BLOCK_SIZE * MCI_BLOCKS_NUM), CARD_BLOCK_SIZE * MCI_BLOCKS_NUM);
      if (mciDmaTxBlks(sector + i, &mciDmaTxConf) == FALSE)
      {
         return (-1);
      }
   }

   return (sector + i - 1);
}

/*------------------------------------------------------------------------------
 function name:   mciDmaReadCard
 description:     MCI reads n bytes from card
 parameters:      source pointer, size in bytes
 returned value:  last read block
------------------------------------------------------------------------------*/
int32 mciDmaReadCard (uint8 *dst, uint32 sector, uint32 size)
{
   uint32 div, rem, i;

   rem = size % (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM);
   div = (size / (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM));

   for (i = 0; i < div; ++i)
   {
      if (mciDmaRxBlks(sector + i, &mciDmaRxConf) == FALSE)
      {
       return (-1);
      }
      memcpy (dst + (i * CARD_BLOCK_SIZE * MCI_BLOCKS_NUM), (const void *)mciDmaRxConf.dstAddr, CARD_BLOCK_SIZE * MCI_BLOCKS_NUM);
   }

   if (rem)
   {
      if (mciDmaRxBlks(sector + i, &mciDmaRxConf) == FALSE)
      {
         return (-1);
      }
      memcpy (dst + (i * CARD_BLOCK_SIZE * MCI_BLOCKS_NUM), (const void *)mciDmaRxConf.dstAddr, rem);
   }

   return (sector + i - 1);
}

/*------------------------------------------------------------------------------
 function name:   mciPrgWrite2Card
 description:     function writes n bytes from src address to card via software.
                   One write is always 512 bytes.
 parameters:      pointer to transmit (TX) buffer,
                  starting block,
                  size in blocks (1 block = 512 bytes)
 returned value:  last written block
------------------------------------------------------------------------------*/
int32 mciPrgWrite2Card  (const uint8 *tx, uint32 block, uint32 numberOfBlocks)
{
   uint32 i;

   if (block + numberOfBlocks >= card.capacity)
   {
      return (-1);
   }

   /* write div times, each write is 512 bytes */
   for (i = 0; i < numberOfBlocks; ++i)
   {
      if (mciTxBlk(tx, block + i) == FALSE)
      {
         return (-1);
      }
   }

   return (block + numberOfBlocks);
}

/*------------------------------------------------------------------------------
 function name:   mciPrgReadCard
 description:     function reads n bytes from card to RX buffer via software.
 parameters:      pointer to receive (RX) buffer,
                  starting block,
                  size in blocks (1 block = 512 bytes)
 returned value:  last read block
------------------------------------------------------------------------------*/
int32 mciPrgReadCard    (uint8 *rx, uint32 block, uint32 numberOfBlocks)
{
   uint32 i;

   if (block + numberOfBlocks >= card.capacity)
   {
      return (-1);
   }

   for (i = 0; i < numberOfBlocks; ++i)
   {
      if (mciRxBlock(rx, block + i) == FALSE)
      {
         uprintf("Read error: %d\n", i);
         return(-1);
      }
   }

   return (block + numberOfBlocks);
}

/*==============================================================================
 Static function definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 function name:   mciSendCmd
 description:     send command from MCI controller to card
 parameters:      command index, argument, response type
 returned value:  card status
------------------------------------------------------------------------------*/
static uint32 mciSendCmd (enum cmdList cmdIndex, uint32 arg, enum response resp)
{
   uint32 status, cmd;

   /* enable the command path state machine & merge the response type */
   cmd = (cmdIndex | resp | MCI_COMMAND_CPSM_ENABLE);
   /* write argument */
   MCI_ARGUMENT = arg;
   /* write command */
   MCI_COMMAND = cmd;
   /* wait for completion */
   do
   {
      status = MCI_STATUS;
   } while (status & MCI_STATUS_CMD_ACTIVE);
   /* clear status register */
   MCI_CLEAR = MCI_WHOLE_STATUS;

   return (status);
}

/*------------------------------------------------------------------------------
 function name:   deselectCard
 description:     deselect card and deactivate it
 parameters:      none
 returned value:  true or false
------------------------------------------------------------------------------*/
static bool deselectCard (void)
{
   uint32 status, response;
   bool returnVal = TRUE;

   /* get card status */
   /*** send CMD13 ***/

   status = mciSendCmd (cmdSEND_STATUS, card.address, respSHORT_RESPONSE);
   response = MCI_RESP0;

   if (response != (csREADY_4_DATA | csTRAN_STATE))
   {
      /* something went wrong - try to stop the data transfer */
      /*** send CMD12 ***/
      status = mciSendCmd (cmdSTOP_TRANSMISSION, 0, respSHORT_RESPONSE);
      /* get card status again */
      /*** send CMD13 ***/
      status = mciSendCmd (cmdSEND_STATUS, card.address, respSHORT_RESPONSE);
      if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
      {
         returnVal = FALSE;                     /* it's over */
      }
   }

   MCI_CLEAR = MCI_WHOLE_STATUS;
   /* deselect card */
   /*** send CMD7 ***/
   status = mciSendCmd(cmdSELECT_CARD, 0, respNO_RESPONSE);
   if (!(status & MCI_STATUS_CMD_SENT))  /* no response */
   {
      returnVal = FALSE;                     /* it's over */
   }

   return (returnVal);
}

/*------------------------------------------------------------------------------
 function name:   checkTranState
 description:     detects if card is in TRAN state
 parameters:      none
 returned value:  true (TRAN) or false (NO TRAN)
------------------------------------------------------------------------------*/
static bool checkTranState (void)
{
   volatile uint32 i;
   uint32 response;

   for (i = 0; i < TIMEOUT_VAL; ++i)
   {
      mciSendCmd(cmdSEND_STATUS, card.address, respSHORT_RESPONSE);
      response = MCI_RESP0;
      if ((response & csTRAN_STATE_MASK) == csTRAN_STATE)
      {
         return (TRUE);
      }
   }

   return (FALSE);      /* timeout */
}

/*------------------------------------------------------------------------------
 function name:   mciDmaTxBlks
 description:     MCI sends multiple blocks to card using GPDMA. To get the fastest
                   possible write speed use this function. This is because the
                   multiple block write command performs faster operation than
                   continous single write command (SD PHY, page 43).
 parameters:      block number, pointer to const struct gpdmaConf
 returned value:  true or false
------------------------------------------------------------------------------*/
static bool mciDmaTxBlks (uint32 sector, const struct gpdmaConf *gpdma)
{
   uint32 status, startBlk;

   /* multiple blocks are written every MCI_BLOCKS_NUM_IRAM */
   startBlk = sector * MCI_BLOCKS_NUM;
   /* startBlk cannot be greater than card size */
   if (startBlk > card.capacity)
   {
      return (FALSE);
   }

   /* check if card is in TRAN(sfer) state */
   if (checkTranState () == FALSE)
   {
      return (FALSE);
   }

   /* prepare transfer- set timeout */
   MCI_DATA_TMR = 0x01000000;
   /* set amount of data & mask out reserved bits */
   MCI_DATA_LEN = (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM) & MCI_DATA_LEN_MASK;
   /* enable Tx interrupts (data end flags & errors */
   MCI_MASK0 = ((DATA_END_INT_MASK) | (ERR_TX_INT_MASK));
   /* flag indicates writing progress */
   mciDataEndFlag = FALSE;
   /* init GPDMA channel */
   mciTxChnl = gpdmaChnl0Init(gpdma);
   /* enable GPDMA channel */
   gpdmaChnl0Enable(mciTxChnl, 0);

   /* init data data transfer */
   /*** send CMD25 ***/
   switch (card.type)
   {
   case cardMMC:  /* I meant that- fall through */
   case cardSD_V2:
   case cardSDSC_V1:
   case cardSDSC_V2:
      /* MMC & SDSC use memory address as address parameter */
      status = mciSendCmd (cmdWRITE_MUL_BLOCKS, startBlk * CARD_BLOCK_SIZE, respSHORT_RESPONSE);
      break;

   case cardSDHC:
      /* SDHC uses blocks as address */
      status = mciSendCmd (cmdWRITE_MUL_BLOCKS, startBlk, respSHORT_RESPONSE);
      break;

   default:
      return (FALSE);
   }

   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      deselectCard ();                        /* test for ongoing transfer and stop it */
      return (FALSE);
   }

   /* start transfer, data flow from card to host, block mode, block size */
   MCI_DATA_CTRL = (MCI_DATA_CTRL_ENABLE | MCI_DATA_CTRL_DMA_EN | MCI_DATA_CTRL_BLOCK_SIZE_512);

   /* wait until the FIFO is empty and block transmission is finished */
   /* mciDataEndFlag is zeroed in MCI ISR */
   while (mciDataEndFlag == FALSE);

   /* multiple block write must be stopped by CMD12- SD PHY, page 75 */
   /*** send CMD12 ***/
   status = mciSendCmd(cmdSTOP_TRANSMISSION, 0, respSHORT_RESPONSE);
   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      deselectCard ();                         /* test for ongoing transfer and stop it */
      return (FALSE);
   }
   MCI_CLEAR = MCI_WHOLE_STATUS;
   MCI_MASK0 = 0;
   MCI_DATA_CTRL = 0;

   return (TRUE);
}

/*------------------------------------------------------------------------------
 function name:   mciDmaRxBlks
 description:     MCI reads multiple blocks from card using GPDMA. To get the fastest
                   possible read speed use this function. This is because the
                   multiple block read command performs faster operation than
                   continous single read command (SD PHY, page 43).
 parameters:      block number, pointer to const struct gpdmaConf
 returned value:  true or false
------------------------------------------------------------------------------*/
static bool mciDmaRxBlks (uint32 sector, const struct gpdmaConf *gpdma)
{
   uint32 status, startBlk;

   /* multiple blocks are written every MCI_BLOCKS_NUM_IRAM */
   startBlk = sector * MCI_BLOCKS_NUM;
   /* startBlk cannot be greather than card size */
   if (startBlk > card.capacity)
   {
      return (FALSE);
   }

   /* check if card is in TRAN(sfer) state */
   if (checkTranState () == FALSE)
   {
      return (FALSE);
   }

   /* prepare transfer- set timeout */
   MCI_DATA_TMR = 0x00100000;
   /* set amount of data & mask out reserved bits */
   MCI_DATA_LEN = (CARD_BLOCK_SIZE * MCI_BLOCKS_NUM) & MCI_DATA_LEN_MASK;
   /* enable Tx interrupts */
   MCI_MASK0 = ((DATA_END_INT_MASK) | (ERR_RX_INT_MASK));
   /* flag indicating transmission progress */
   mciDataEndFlag = FALSE;
   /* init GPDMA channel */
   mciRxChnl = gpdmaChnl1Init(gpdma);
   /* enable GPDMA channel */
   gpdmaChnl1Enable(mciRxChnl, 0);

   /* init data data transfer */
   /*** send CMD17 ***/
   switch (card.type)
   {
   case cardMMC:  /* I meant that- fall through */
   case cardSD_V2:
   case cardSDSC_V1:
   case cardSDSC_V2:
      /* MMC & SDSC use memory address as address parameter */
      status = mciSendCmd (cmdREAD_MUL_BLOCKS, startBlk * CARD_BLOCK_SIZE, respSHORT_RESPONSE);
      break;

   case cardSDHC:
      /* SDHC uses blocks as address */
      status = mciSendCmd (cmdREAD_MUL_BLOCKS, startBlk, respSHORT_RESPONSE);
      break;

   default:
      return (FALSE);
   }

   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      deselectCard ();                        /* test for ongoing transfer and stop it */
      return (FALSE);
   }

   /* start transfer, data flow from card to host, block mode, block size */
   MCI_DATA_CTRL =   (MCI_DATA_CTRL_ENABLE | MCI_DATA_CTRL_DIRECTION_2H |
                     MCI_DATA_CTRL_DMA_EN | MCI_DATA_CTRL_BLOCK_SIZE_512);

   /* wait till the end of transfer- the flag is erased by ISR */
   while (mciDataEndFlag == FALSE);

   /* multiple block read must be stopped by CMD12- SD PHY, page 75 or 41 */
   /*** send CMD12 ***/
   status = mciSendCmd(cmdSTOP_TRANSMISSION, 0, respSHORT_RESPONSE);
   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      deselectCard ();                        /* test for ongoing transfer and stop it */
      return (FALSE);
   }
   MCI_CLEAR = MCI_WHOLE_STATUS;
   MCI_MASK0 = 0;
   MCI_DATA_CTRL = 0;

   return (TRUE);
}

/*------------------------------------------------------------------------------
 function name:   mciTxBlk
 description:     write 1 block (512 bytes) to card
 parameters:      pointer to TX buffer, starting block
 returned value:  true or false
------------------------------------------------------------------------------*/
static bool mciTxBlk (const uint8 *tx, uint32 block)
{
   volatile uint32 i = 0;
   uint32 status;
   bool returnVal = TRUE;

   /* put card into the Transfer State */
   /*** send CMD7 ***/
   status = mciSendCmd (cmdSELECT_CARD, card.address, respSHORT_RESPONSE);
   if (!(status & MCI_STATUS_CMD_RESP_END))
   {
      return (FALSE); /* no response */
   }

   /* no 4-bit bus here */

   /* prepare transfer- set timeout */
   MCI_DATA_TMR = 0x00100000;
   /* set amount of data & mask out reserved bits */
   MCI_DATA_LEN = CARD_BLOCK_SIZE & MCI_DATA_LEN_MASK;
   /* enable transfer, data flow from MCI to card, block mode, block size */
   MCI_DATA_CTRL = (MCI_DATA_CTRL_ENABLE | MCI_DATA_CTRL_BLOCK_SIZE_512);

   /* init data data transfer */
   /*** send CMD24 ***/
   switch (card.type)
   {
   case cardMMC:  /* I meant that- fall through */
   case cardSD_V2:
   case cardSDSC_V1:
   case cardSDSC_V2:
      /* MMC & SDSC use memory address as address parameter */
      status = mciSendCmd (cmdWRITE_SINGLE_BLOCK, block * CARD_BLOCK_SIZE, respSHORT_RESPONSE);
      break;

   case cardSDHC:
      status = mciSendCmd (cmdWRITE_SINGLE_BLOCK, block, respSHORT_RESPONSE);
      break;

   default:
      return (FALSE);
   }

   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      deselectCard ();                           /* test for ongoing transfer and stop it */
      return (FALSE);
   }

   /* start sending data fo MCI fifo */
   do
   {
      while ( !(MCI_STATUS & MCI_STATUS_TX_FIFO_FULL) && (i < (CARD_BLOCK_SIZE / sizeof (uint32))) )
      {
         MCI_FIFO = *(uint32 *)(tx + i * sizeof(uint32));
         i++;
      }
   } while ( !(MCI_STATUS & (MCI_STATUS_DATA_TIMEOUT | MCI_STATUS_TX_UNDERRUN |
                              MCI_STATUS_DATA_END | MCI_STATUS_DATA_BLOCK_END))
                              && (i < (CARD_BLOCK_SIZE / sizeof (uint32))) );

   /* check if correct number of bytes was written */
   if (i != (CARD_BLOCK_SIZE / sizeof (uint32)))
   {
      deselectCard ();                           /* test for ongoing transfer and stop it */
      return (FALSE);
   }

   /* check if we were to slow to write data */
   if (MCI_STATUS & MCI_STATUS_TX_UNDERRUN)
   {
      deselectCard ();                           /* test for ongoing transfer and stop it */
      return (FALSE);
   }

   /* wait till fifo is empty */
   while ( !(MCI_STATUS & MCI_STATUS_TX_FIFO_EMPTY));
   /* clear interrupts */
   MCI_CLEAR = MCI_WHOLE_STATUS;

   /* wait till card has processed all data */
   i = 0;
   do
   {
      mciSendCmd (cmdSEND_STATUS, card.address, respSHORT_RESPONSE);
      status = MCI_RESP0;
      i++;
   }while ((status != (csREADY_4_DATA | csTRAN_STATE)) && (i < TIMEOUT_VAL * 100));

   /* reset data control register */
   MCI_DATA_CTRL = 0;
   for (i = 0; i < TIMEOUT_VAL; ++i);

   /* test for ongoing transfer and stop it if so; deselect card */
   returnVal = deselectCard ();

   return (returnVal);
}

/*------------------------------------------------------------------------------
 function name:   mciRxBlock
 description:     write 1 block (512 bytes) to card
 parameters:      pointer to TX buffer, starting block
 returned value:  true or false
------------------------------------------------------------------------------*/
static bool mciRxBlock (uint8 *rx, uint32 block)
{
   volatile uint32 i;
   uint32 status;
   bool returnVal;

   /* select card for further usage */
   /*** send CMD7 ***/
   status = mciSendCmd(cmdSELECT_CARD, card.address, respSHORT_RESPONSE);
   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      return (FALSE);
   }

   /* no 4-bit mode here */

   /* prepare transfer- set timeout */
   MCI_DATA_TMR = 0x00100000;
   /* set amount of data & mask out reserved bits */
   MCI_DATA_LEN = CARD_BLOCK_SIZE & MCI_DATA_LEN_MASK;
   /* enable transfer, data flow from card to MCI, block mode, block size */
   MCI_DATA_CTRL = (MCI_DATA_CTRL_ENABLE | MCI_DATA_CTRL_DIRECTION_2H | MCI_DATA_CTRL_BLOCK_SIZE_512);

   /* init data data transfer */
   /*** send CMD17 ***/
   switch (card.type)
   {
   case cardMMC:  /* I meant that- fall through */
   case cardSD_V2:
   case cardSDSC_V1:
   case cardSDSC_V2:
      /* MMC & SDSC use memory address as address parameter */
      status = mciSendCmd (cmdREAD_SINGLE_BLOCK, block * CARD_BLOCK_SIZE, respSHORT_RESPONSE);
      break;

   case cardSDHC:
      status = mciSendCmd (cmdREAD_SINGLE_BLOCK, block, respSHORT_RESPONSE);
      break;

   default:
      return (FALSE);
   }

   if (!(status & MCI_STATUS_CMD_RESP_END))  /* no response */
   {
      deselectCard();
      return (FALSE);
   }

   i = 0;
   do
   {
      while ((MCI_STATUS & MCI_STATUS_RX_DATA_AVLBL) && (i < (CARD_BLOCK_SIZE / sizeof(uint32))))
      {
         /* save data from MCI FIFO in RX buffer */
         *(uint32 *)(rx + i * sizeof (uint32)) = MCI_FIFO;
         i++;
      }
   } while (!(MCI_STATUS & (MCI_STATUS_DATA_TIMEOUT | MCI_STATUS_RX_OVERRUN | MCI_STATUS_DATA_END | MCI_STATUS_DATA_BLOCK_END))
         && (i < (CARD_BLOCK_SIZE/sizeof(uint32))));

   /* did we get the correct number of bytes? */
   if (i != CARD_BLOCK_SIZE / sizeof(uint32))
   {
      deselectCard();
      return (false);
   }

   /* clear status */
   MCI_CLEAR = MCI_WHOLE_STATUS;
   /* reset data control register in MCI */
   MCI_DATA_CTRL = 0;
   for (i = 0; i < TIMEOUT_VAL; ++i);

   /* test for ongoing transfer and stop it if so; deselect card */
   returnVal = deselectCard();

   return (returnVal);
}

/*------------------------------------------------------------------------------
 function name:   dataErrProcess
 description:     function called by MCI ISR to process data errors
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
static void dataErrProcess (void)
{
   uint32 mciStatus;

   mciStatus = MCI_STATUS;

   if (mciStatus & MCI_STATUS_DATA_CRC_FAIL)
   {
      MCI_CLEAR = MCI_CLEAR_DATA_CRC_FAIL_CLR;
   }
   if (mciStatus & MCI_STATUS_DATA_TIMEOUT)
   {
      MCI_CLEAR = MCI_CLEAR_DATA_TIMEOUT_CLR;
   }
   if (mciStatus & MCI_STATUS_TX_UNDERRUN)
   {
      MCI_CLEAR = MCI_CLEAR_TX_UNDERRUN_CLR;
   }
   if (mciStatus & MCI_STATUS_RX_OVERRUN)
   {
      MCI_CLEAR = MCI_CLEAR_RX_OVERRUN_CLR;
   }
   if (mciStatus & MCI_STATUS_START_BIT_ERR)
   {
      MCI_CLEAR = MCI_CLEAR_START_BIT_ERR_CLR;
   }
}

/*------------------------------------------------------------------------------
 function name:   dataEndProcess
 description:     function called by MCI ISR to process write/read blocks
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
static void dataEndProcess (void)
{
   uint32 mciStatus;

   mciStatus = MCI_STATUS;

   /* end of transmission */
   if (mciStatus & MCI_STATUS_DATA_END)
   {
# if MCI_TEST
      dataEndCounter ++;
# endif
      /* clear interrupt status */
      MCI_CLEAR = MCI_CLEAR_DATA_END_CLR;
      /* clear the flag */
      mciDataEndFlag = TRUE;
   }

   if (mciStatus & MCI_STATUS_DATA_BLOCK_END)
   {
# if MCI_TEST
      dataBlkEndCounter ++;
# endif
      /* clear interrupt status */
      MCI_CLEAR = MCI_CLEAR_DATA_BLOCK_END_CLR;
      /* clear the flag */
      mciBlkEndFlag = TRUE;
   }
}

/*------------------------------------------------------------------------------
 function name:   cmdProcess
 description:     called by MCI ISR to process SD commands
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
static void cmdProcess (void)
{
   uint32 mciStatus;

   mciStatus = MCI_STATUS;

   if (mciStatus & MCI_STATUS_CMD_CRC_FAIL)
   {
      MCI_CLEAR = MCI_CLEAR_CMD_CRC_FAIL_CLR;
   }
   if (mciStatus & MCI_STATUS_CMD_TIMEOUT)
   {
      MCI_CLEAR = MCI_CLEAR_CMD_TIMEOUT_CLR;
   }
   if (mciStatus & MCI_STATUS_CMD_RESP_END)
   {
      MCI_CLEAR = MCI_CLEAR_CMD_RESP_END_CLR;
   }
   if (mciStatus & MCI_STATUS_CMD_SENT)
   {
      MCI_CLEAR = MCI_CLEAR_CMD_SENT_CLR;
   }

}

/*------------------------------------------------------------------------------
 function name:   dummyService
 description:     does nothing
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
static void dummyService (void)
{
   return;
}
/*==============================================================================
 Static ISR definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 function name:   mciIsr
 description:     MCI interrupt service routine
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
void mciIsr (void)
{
   uint32 status;

   status = MCI_STATUS;

   if (status & (DATA_ERR_INT_MASK))
   {
     dataErrProcess ();
     VICVectAddr = 0;
     return;
   }
   if (status & (DATA_END_INT_MASK))
   {
      dataEndProcess ();
      VICVectAddr = 0;
      return;
   }

   if (status & (CMD_INT_MASK))
   {
      cmdProcess ();
      VICVectAddr = 0;
      return;
   }
}
/******************************************************************************
* END OF FILE
******************************************************************************/

